Userについて考える 2024最新版 マネーフォワードの事例を添えて
持ち時間が10分あるけど、5分くらいで解説を終えて残り5分はディスカッションに当てたい。
(多分無理)
お題はこれ。
詳細はここにも少し書いた
マネーフォワードにはさまざまな金融ドメインのBtoB SaaSがある。
(みんなが知ってるのは家計簿アプリのマネーフォワード MEだと思うが、実は弊社の利益の多くはBtoB SaaSが稼いでる)
以前、社内でこんな内容が発生した。
https://gyazo.com/ccd49d920e89ff58b6f8bc25e3971044
一部プロダクトで「ログインしないユーザー」が存在する……そんなことある?!?!!!
………あります。
例えば、マネーフォワード クラウド勤怠を使う場合。
従業員はEmailが発行されないケースがある。またギグワーカー(タイミーさんやメルカリハローさんとか)な人が業務に携わる場合、このような自体は生まれることがある。
とある勤怠サービスでは「お弁当発注」機能が生まれたことがあるらしい。
厳密にいえばこれらは「勤怠」のビジネスドメインではない。
だがしかし、実態となるワークフローでは工場がある地域に飲食店がないなどの理由から大量に弁当を発注するケースが起こり得る。
こういった需要からサービスやモデルというのは肥大化する傾向がある。
閑話休題。
話を戻す。このようにメールアドレスを持たない従業員がサービスを利用したい、ということは現実の業務で発生する。
我々は多くの場合 User モデルを定義している、だがしかしこれは Person でも問題はないはず。
Railsはテーブル名を複数形で表すので、Person(単数形) は People(複数形) テーブルに格納される。
https://gyazo.com/33d2e94e34511c729d42d3146e5c6102
実際にその変換を行っているコードを先日土曜に開催したKyoto.rbのイベントでコードリーディングしていたので軽く紹介する。
code:ruby:activesupport/lib/active_support/inflections.rb
module ActiveSupport
Inflector.inflections(:en) do |inflect|
inflect.plural(/$/, "s")
inflect.plural(/s$/i, "s")
inflect.plural(/^(ax|test)is$/i, '\1es')
(中略)
inflect.irregular("person", "people")
inflect.irregular("man", "men")
inflect.irregular("child", "children")
inflect.irregular("sex", "sexes")
inflect.irregular("move", "moves")
inflect.irregular("zombie", "zombies")
inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police))
end
end
User は id と created_atだけあればいいは本当か?
当日、イベント内では id と created_at だけあればいいのではないか?という話があった。
https://gyazo.com/ddb0e4ae1b8b67c2a5ae20198cedd3db
Userは確かにファットになりがち
先ほどの事例のようにマネーフォワード クラウド勤怠やマネーフォワード クラウド給与のようなサービスのエンドユーザーが従業員である場合はこの設計でも問題はないはず。
https://gyazo.com/9d5393bdb681c8e222bc49e65ea253ee
だがしかし、実際のプロダクトでここまで簡潔にユーザーを表現することは少ない(はず)。
それは何故か?
理由はいろいろありそう。
過度な正規化は検索のパフォーマンスが劣化することがあるから
データとしての正しさと開発としての利便性がトレードオフされて、正規化ではなく非正規化を選択するから
User が持つ関心が更新と検索の両方に存在する
Userモデルの難しさは検索性を担保しつつ、関心として更新も頻繁に行われやすい性質を持っているからではないかと思う。
参考にできそうだと思った設計
user_credentials
user_profiles
user_registrations
user_registration_credentialsまで含めるかは若干議論の余地がある気がする
email_verifications
あたりは参考にしつつ、どこまでを正規化するかは自分たちのサービスをどうしたいかで決めることになると思う。
個人的には user_registrations と user_profiles 、 user_credentials あたりは分けたいなと考える。
そもそも User というワードが実態をきちんと表せていないことが問題。
管理画面を扱うなら Staff のようなモデルに分ける、経理部が扱うなら AccountingMembers (経理部は英語でAccounting Department)。
https://gyazo.com/b3aec7da60a2d014eded3b3a7f615f7f
User や実態の業務を表すモデリング
弊社は会計のサービスも開発しているが、この会計事務所が会社からの委託により会計業務を担当することがある。
エンドユーザーは同じアカウントで横断して異なる事務所(会社)の情報を閲覧したい。
その場合、複数の事務所(会社)を横断してログインしたいなどの複雑さを持つことになる。
これは先ほどの User というワードだけでは表現できない(表現しにくい)
関心を分離する
正確には関心が異なる User を同一のモデルで表現するとモデルの関心が歪み、ファットモデルになってしまう。
ファットモデルは誤解を生みがちだがコードの行数が多いことは必ずしもファットモデルを意味しない。
単一責任の原則に違反する場合をファットモデルと呼ぶ(と思ってる)
存在しない User というビッグワード
誰もが作りがちな User だがそのような概念は(実際には)存在しない。
実在する User を知ることがImmutableな設計を実装することにつながる。
https://gyazo.com/20f302ec9ab4cb22906d94035189c04e
どうするといいか?
User を知るためには User のいるところに足を運ぼう。
会計のサービスを作っているなら経理部、勤怠のサービスを作ってるなら実際に勤怠を使う会社、人事管理のサービスを作っているなら人事部。
まとめ
現場にいかなければ見えないワークフロー、ふるまいが存在する。
もっと現場に足を運んで、Big User をきちんと分解して、単一責任の原則にそったImmutableな User をDiscoveryしていこうな!
ここからディスカッションしたい
時間があれば話したいが、無理なら自由に書き込んでくれ!
自分たちのサービスにおける最小構成の User はどのような設計になっていますか?
User 以外にどのようなモデルが必要になりますか?